/*
 * $Id: BaseController.java 42 2013-04-17 15:33:59Z gabakyan $
 * $Author: gabakyan $
 * $Revision: 42 $
 * $Date: 2013-04-17 15:33:59 +0000 (Wed, 17 Apr 2013) $
 *
 * Copyright (c) 2013 Supply Chain Intelligence (SCI), Inc.
 * http://www.scintelligence.com/, Email: info@scintelligence.com
 * All rights reserved.
 *
 * This file is part of Logistics Map.
 *
 * Logistics Map is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * Logistics Map is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Logistics Map.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.sci.logisticsmap.web.controller;

import com.sci.logisticsmap.service.support.ServiceException;
import com.sci.logisticsmap.support.MessageKeyedException;
import com.sci.logisticsmap.support.MessageSourceAccessHelper;
import com.sci.logisticsmap.support.MessagedException;
import com.sci.logisticsmap.support.converter.ConversionUtilities;
import com.sci.logisticsmap.support.model.ResponseStatus;
import com.sci.logisticsmap.support.model.ResponseWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.Serializable;

/**
 * The Controller base class for processing view/ajax requests.
 *
 * @author gabakyan@gmail.com (Last modified by $Author: gabakyan $)
 * @version $Revision: 42 $
 */
public abstract class BaseController {
    /**
     * The base path.
     */
    public static final String PATH_BASE = "/";

//    /**
//     * The ajax path.
//     */
    //public static final String PATH_AJAX = "/ajax/";
    /**
     * The resources path.
     */
    public static final String PATH_RESOURCES = "/resources/";
    /**
     * The admin path.
     */
    public static final String PATH_ADMIN = "/admin/";

    /**
     * The logger.
     */
	protected Logger logger;

    /**
     * The message source access helper.
     */
    @Autowired
    protected MessageSourceAccessHelper messageSourceAccessHelper;

    /**
     * The http messages converter
     * that can read and write JSON using <a href="http://jackson.codehaus.org/">Jackson's</a>
     * {@link org.codehaus.jackson.map.ObjectMapper}.
     */
    @Autowired
    protected MappingJacksonHttpMessageConverter jacksonMessageConverter;

    /**
     * The conversion utilities.
     */
    @Autowired
    protected ConversionUtilities conversionUtilities;

//    /**
//     * The session briefcase.
//     */
//    @Autowired
//    protected SessionBriefcase sessionBriefcase;

    /**
     * The default constructor.
     * Initializes a Controller base class.
     */
    public BaseController() {
        logger = LoggerFactory.getLogger(getClass());
    }

    /**
     * The post construct initialization method.
     */
    @PostConstruct
    public void init() {
    }

    /**
     * Adds attributes to the model.
     *
     * @param model the model.
     */
    @ModelAttribute
    public void addAttributesToModel(Model model) {
//        SessionUserDTModel sessionUser = sessionBriefcase.getUser();

        //if (SecurityContextHelper.isAuthenticatedUser()) {
        /*SessionUserDTModel sessionUser = SecurityContextHelper.getAuthenticatedUserDTModel();
        if (sessionUser != null) {
            StringBuilder fullNameBuilder = new StringBuilder();
            fullNameBuilder.append(sessionUser.getFirstName()).append(" ").append(sessionUser.getLastName());
            model.addAttribute("sessionUserFullName", fullNameBuilder.toString());
        }*/
    }

    /**
     * Adds the message to the model.
     *
     * @param model the model.
     * @param message the message.
     */
    protected void addMessageToModel(Model model, String message) {
        model.addAttribute("message", message);
    }

    /**
     * Adds the message key to the model.
     *
     * @param model the model.
     * @param messageKey the message key.
     */
    protected void addMessageKeyToModel(Model model, String messageKey) {
        model.addAttribute("messageKey", messageKey);
    }

    /**
     * Adds error message to the model.
     *
     * @param model the model.
     * @param errorMessage the error message.
     */
    protected void addErrorMessageToModel(Model model, String errorMessage) {
        model.addAttribute("errorMessage", errorMessage);
    }

    /**
     * Adds error message key to the model.
     *
     * @param model the model.
     * @param errorMessageKey the error message key.
     */
    protected void addErrorMessageKeyToModel(Model model, String errorMessageKey) {
        model.addAttribute("errorMessageKey", errorMessageKey);
    }

    /**
     * Adds the custom message to the model.
     *
     * @param model the model.
     * @param messageName the message name.
     * @param message the message.
     */
    protected void addCustomMessageToModel(Model model, String messageName, String message) {
        model.addAttribute(messageName, message);
    }

    /**
     * Adds the custom message key to the model.
     *
     * @param model the model.
     * @param messageName the message name.
     * @param messageKey the message key.
     */
    protected void addCustomMessageKeyToModel(Model model, String messageName, String messageKey) {
        model.addAttribute(messageName, messageKey);
    }

    /**
     * Adds an exception to the model.
     *
     * @param model the model.
     * @param e the exception.
     */
    protected void addExceptionToModel(Model model, Exception e) {
        String errorMessage = null;
        if (e.getClass() == MessageKeyedException.class) {
            errorMessage = messageSourceAccessHelper.getMessage(e.getMessage());
        } else {
            errorMessage = e.getMessage();

            if (e.getClass() == MessagedException.class) {
                logger.error(errorMessage, e.getCause());
            } else {
                logger.error(errorMessage, e);
            }
        }
        addErrorMessageToModel(model, errorMessage);
    }

    /**
     * Adds an exception to the response wrapper.
     *
     * @param responseWrapper the response wrapper.
     * @param e the exception.
     */
    protected <Response extends /*BaseResponse*/Serializable> void addExceptionToResponseWrapper(ResponseWrapper<Response> responseWrapper, Exception e) {
        addExceptionToResponseWrapper(responseWrapper, ResponseStatus.ERROR, e);
    }

    /**
     * Adds a status and an exception to the response wrapper.
     *
     * @param responseWrapper the response wrapper.
     * @param status the status.
     * @param e the exception.
     */
    protected <Response extends /*BaseResponse*/Serializable> void addExceptionToResponseWrapper(ResponseWrapper<Response> responseWrapper, int status, Exception e) {
        responseWrapper.setStatus(status);

        String errorMessage;
        if (e.getClass() == ServiceException.class) {
            if (e.getCause() != null) {
                errorMessage = e.getCause().getMessage();
            } else {
                errorMessage = e.getMessage();
            }
        } else if (e.getClass() == MessageKeyedException.class) {
            errorMessage = messageSourceAccessHelper.getMessage(e.getMessage());
        } else {
            errorMessage = e.getMessage();

            /*if (e.getClass() == MessagedException.class) {
                logger.error(errorMessage, e.getCause());
            } else {
                logger.error(errorMessage, e);
            }*/
        }
        responseWrapper.setMessage(errorMessage);
    }

    /**
     * Writes the wrapped response object (into the response) using the custom media type.
     *
     * @param responseWrapper the response wrapper.
     * @param mediaType the media type.
     * @param response the response.
     */
    protected void writeResponseUsingCustomMediaType(ResponseWrapper responseWrapper, MediaType mediaType, HttpServletResponse response) {
        //MediaType jsonMediaType = MediaType.APPLICATION_JSON;
        //if (jacksonMessageConverter.canWrite(responseWrapper.getClass(), jsonMediaType)) {
            try {
                jacksonMessageConverter.write(responseWrapper, mediaType, new ServletServerHttpResponse(response));
            } catch (HttpMessageNotWritableException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        //}
    }

    /**
     * Builds the given path redirect string.
     *
     * @param path the path.
     *
     * @return The path redirect string.
     */
    protected String buildRedirectToPath(String path) {
        return buildRedirectToPath(path, "");
    }

    /**
     * Builds the given path redirect string
     * and uses the given query string.
     *
     * @param path the path.
     * @param queryString the query string.
     *
     * @return The path redirect string.
     */
    protected String buildRedirectToPath(String path, String queryString) {
        return new StringBuilder("redirect:").append(path).append(queryString).toString();
    }
}
